#include "stdafx.h"

#include "gp_Ax3.h"
#include "gp_Ax1.h"
#include "gp_Pnt.h"
#include "gp_Ax2.h"
#include "gp_Trsf.h"
#include "gp_Vec.h"
#include "gp_Cone.h"
#include "gp.h"


 gp_Cone::gp_Cone () :
radius (DBL_MAX),
semiAngle (M_PI * 0.25)
{ }

 gp_Cone::gp_Cone (const gp_Ax3& A3,
			 const double Ang,
			 const double Radius) :
			 pos(A3),
			 radius (Radius),
			 semiAngle (Ang)
{
  double val = Ang;
  if (val < 0) val = - val;
  Standard_ConstructionError_Raise_if
  (radius < 0. ||
	  val <= gp::Resolution() ||
	  M_PI * 0.5 - val <= gp::Resolution(), "");
}

 void gp_Cone::SetAxis     (const gp_Ax1& A1)
{ pos.SetAxis (A1); }

 void gp_Cone::SetLocation (const gp_Pnt& Loc)
{ pos.SetLocation (Loc); }

 void gp_Cone::SetPosition (const gp_Ax3& A3)
{ pos = A3; }

 void gp_Cone::SetRadius (const double R)
{
	 Standard_ConstructionError_Raise_if
	 (R < 0.0, "");
  radius = R;
}

 void gp_Cone::SetSemiAngle (const double Ang)
{
  double val = Ang;
  if (val < 0) val = - val;
  Standard_ConstructionError_Raise_if
  (val <= gp::Resolution() ||
	  M_PI * 0.5 - val <= gp::Resolution(), "");
  semiAngle = Ang;
}

 gp_Pnt gp_Cone::Apex () const
{
  gp_XYZ Coord = pos.Direction ().XYZ ();
  Coord.Multiply (-radius / tan (semiAngle));
  Coord.Add (pos.Location ().XYZ());
  return gp_Pnt (Coord);
}

 void gp_Cone::UReverse()
{ pos.YReverse(); }

 void gp_Cone::VReverse()
{ pos.ZReverse(); semiAngle = -semiAngle; }

 bool gp_Cone::Direct() const
{ return pos.Direct(); }

 const gp_Ax1& gp_Cone::Axis () const
{ return pos.Axis(); }

 const gp_Pnt& gp_Cone::Location () const
{ return pos.Location(); }

 const gp_Ax3& gp_Cone::Position () const
{ return pos; }

 double gp_Cone::RefRadius () const
{ return radius; }

 double gp_Cone::SemiAngle () const
{ return semiAngle; }

 gp_Ax1 gp_Cone::XAxis () const
{ return gp_Ax1 (pos.Location(), pos.XDirection()); }

 gp_Ax1 gp_Cone::YAxis () const
{ return gp_Ax1 (pos.Location(), pos.YDirection()); }

 void gp_Cone::Rotate (const gp_Ax1& A1,
			     const double Ang)
{pos.Rotate (A1, Ang);}

 gp_Cone gp_Cone::Rotated (const gp_Ax1& A1,
				 const double Ang) const
{
  gp_Cone C = *this;
  C.pos.Rotate (A1, Ang);
  return C;
}

 void gp_Cone::Scale (const gp_Pnt& P,
			    const double S)
{
  pos.Scale (P, S);      
  radius *= S;
  if (radius < 0) radius = - radius;
}

 gp_Cone gp_Cone::Scaled (const gp_Pnt& P,
				const double S) const
{
  gp_Cone C = *this;
  C.pos.Scale (P, S);
  C.radius *= S;
  if (C.radius < 0) C.radius = - C.radius;
  return C;
}

 void gp_Cone::Transform (const gp_Trsf& T)
{
  pos.Transform (T);
  radius *= T.ScaleFactor();
  if (radius < 0) radius = - radius;
}

 gp_Cone gp_Cone::Transformed (const gp_Trsf& T) const
{
  gp_Cone C = *this;
  C.pos.Transform (T);
  C.radius *= T.ScaleFactor();
  if (C.radius < 0) C.radius = - C.radius;
  return C;
}

 void gp_Cone::Translate (const gp_Vec& V)
{ pos.Translate (V); }

 gp_Cone gp_Cone::Translated (const gp_Vec& V) const
{
  gp_Cone C = *this;
  C.pos.Translate (V);
  return C;
}

 void gp_Cone::Translate (const gp_Pnt& P1,
				const gp_Pnt& P2)
{ pos.Translate (P1, P2); }

 gp_Cone gp_Cone::Translated (const gp_Pnt& P1,
				    const gp_Pnt& P2) const
{
  gp_Cone C = *this;
  C.pos.Translate (P1, P2);
  return C;
}


 void gp_Cone::Coefficients
	 (double& A1, double& A2, double& A3, 
	 double& B1, double& B2, double& B3,
	 double& C1, double& C2, double& C3,
	 double& D) const
 {
	 // Dans le repere du cone :
	 // X**2 + Y**2 - (radius + Z * Tan(semiAngle))**2 = 0.0
	 gp_Trsf T;
	 T.SetTransformation (pos);
	 double KAng = tan (semiAngle);
	 double T11 = T.Value (1, 1);
	 double T12 = T.Value (1, 2);
	 double T13 = T.Value (1, 3);
	 double T14 = T.Value (1, 4);
	 double T21 = T.Value (2, 1);
	 double T22 = T.Value (2, 2);
	 double T23 = T.Value (2, 3);
	 double T24 = T.Value (2, 4);
	 double T31 = T.Value (3, 1) * KAng;
	 double T32 = T.Value (3, 2) * KAng;
	 double T33 = T.Value (3, 3) * KAng;
	 double T34 = T.Value (3, 4) * KAng;
	 A1 = T11 * T11 + T21 * T21 - T31 * T31;
	 A2 = T12 * T12 + T22 * T22 - T32 * T32;
	 A3 = T13 * T13 + T23 * T23 - T33 * T33;
	 B1 = T11 * T12 + T21 * T22 - T31 * T32;
	 B2 = T11 * T13 + T21 * T23 - T31 * T33;
	 B3 = T12 * T13 + T22 * T23 - T32 * T33;
	 C1 = T11 * T14 + T21 * T24 - T31 * (radius + T34);
	 C2 = T12 * T14 + T22 * T24 - T32 * (radius + T34);
	 C3 = T13 * T14 + T23 * T24 - T33 * (radius + T34);
	 D = T14*T14 + T24*T24 - radius*radius - T34*T34 - 2.0*radius*T34;  
 }

 void gp_Cone::Mirror (const gp_Pnt& P)
 { pos.Mirror (P); }

 gp_Cone gp_Cone::Mirrored (const gp_Pnt& P) const
 {
	 gp_Cone C = *this;
	 C.pos.Mirror (P);
	 return C;
 }

 void gp_Cone::Mirror (const gp_Ax1& A1)
 { pos.Mirror (A1); }

 gp_Cone gp_Cone::Mirrored (const gp_Ax1& A1) const
 {
	 gp_Cone C = *this;
	 C.pos.Mirror (A1);
	 return C;
 }

 void gp_Cone::Mirror (const gp_Ax2& A2)
 { pos.Mirror (A2); }

 gp_Cone gp_Cone::Mirrored (const gp_Ax2& A2) const
 {
	 gp_Cone C = *this;
	 C.pos.Mirror (A2);
	 return C;
 }

